package org.raymond.iworks.study.mq.rabbitmq.stream;

/**
 * @author raymond
 * @version V1.0
 * @Description: TODO
 */

/**
 * 超级流是位于流之上的结构,允许对一组流进行逻辑分组.
 *     消息不经过交换,它们直接进入分区流.但是客户机库使用拓扑信息来确定将消息路由到哪里以及从哪里使用它们.
 *     让我们来谈谈房间里的大象:它与kafka相比如何?我们可以将一个超级流比作一个Kafka主题,将一个流比作一个Kafka主题的分区.
 * RabbitMQ流是一级的、独立命名的对象,而Kafka分区是Kafka主题的从属对象.
 * 这个解释遗漏了很多细节,没有真正的1对1映射,但对于我们在这篇文章中的观点来说已经足够准确了。
 *     超级流还利用单个活动消费者在消费者处理期间保持分区内消息的顺序.下面是更多信息.
 * 不要误解我们的意思,超级流不会弃用单个流,也不会让它们变得无用.它们也不是流版本2.0,因为我们一开始就把流做错了.
 * 超级流位于流之上,它们带来了自己的一套特性和功能.您可以在适合的地方继续使用单个流,也可以为更苛刻的用例探索超级流.
 *     应用程序发布到超级流的消息必须转到其中一个分区.应用程序可以选择分区,在客户机库的帮助下,代理不处理路由.
 * 这是灵活的,避免了服务器端的瓶颈.
 *     应用程序必须提供至少一条信息:从消息中提取的路由密钥.下面的代码片段展示了应用程序如何通过流Java客户端库提供这些代码:
 * Producer producer = environment.producerBuilder()
 *     .superStream("invoices") // set the super stream name
 *     .routing(message -> message.getProperties().getMessageIdAsString()) // extract routing key
 *     .producerBuilder()
 *     .build();
 * producer.send(...);
 *     发布与常规流保持相同,生产者配置只是略有不同.发布到流或超级流不会对应用程序的代码产生太大影响.
 *     信息到哪里去了?在本例中,库通过使用MurmurHash3对路由键进行散列来选择流分区.这个散列函数提供了良好的一致性、性能和可移植性,
 * 使其成为一个很好的默认选择.在我们的示例中,路由键是发票ID,因此发票应该均匀地分布在各个分区上.如果路由键是客户ID,
 * 我们就可以保证给定客户的所有发票都在同一个分区上.下面是一个可以利用这一点的用例:使用适当的基于时间戳的偏移量规范
 * 对给定时间段的每个客户进行报告.
 *     说到处理,让我们看看如何从超级流中消费.
 * 从一个超级流消费
 *     超级流的分区是常规流,因此应用程序可以像往常一样使用它们.但这意味着要了解超级流的拓扑结构,而我们将其作为逻辑实体出售,
 * 应用程序将其视为单个流.幸运的是,客户机库可以在代理的帮助下实现这一点,使其对应用程序完全透明.
 *     客户端库可以实现一种众所周知的设计模式,并提供一个复合消费者,它可以同时从超级流的所有分区中消费:
 * 客户端库提供了一个复合消费者,它同时从所有分区中消费数据.然后,应用程序将超级流视为单独的流.但这还不够,
 * 以这种方式实现的复合消费者有其局限性:如果为了冗余和可伸缩性而启动同一应用程序的多个实例,它们将消耗相同的消息,从而重复处理.
 * 所有这些都需要协调,幸运的是,我们可以将单个活动消费者的语义应用于我们的超级流组合消费者.
 * 现在启用了单个活动消费者后,复合消费者的实例将与代理协调,以确保在给定分区上一次只有一个消费者.
 * 结合超级流消费者和单个活跃消费者.对于给定的组,一个分区上一次只有一个活动消费者.
 * 好消息是,所有这些都是实现细节.应用程序实例可以上下浮动,消费者将根据单活动-消费者语义激活或停用.
 * Consumer consumer = environment.consumerBuilder()
 *     .superStream("invoices") // set the super stream name
 *     .name("application-1") // set the consumer name (mandatory)
 *     .singleActiveConsumer() // enable single active consumer
 *     .messageHandler((context, message) -> {
 *         // message processing
 *     })
 *     .build();
 * 这与常规流的消费者类似,只是配置发生了变化,更重要的是,消息处理代码保持不变.
 */
public class SuperStreamTask {
}
